#nullable enable
using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace ERP.Api.Infrastructure.ModelBinding
{
    /// <summary>
    /// 将空字符串自动绑定为 null，并解析常见可空基础类型。
    /// </summary>
    public class EmptyStringToNullBinder : IModelBinder
    {
        private readonly Type _targetType;
        public EmptyStringToNullBinder(Type targetType) => _targetType = targetType;

        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (valueResult == ValueProviderResult.None)
            {
                return Task.CompletedTask;
            }
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueResult);

            var raw = valueResult.FirstValue;
            if (string.IsNullOrWhiteSpace(raw))
            {
                bindingContext.Result = ModelBindingResult.Success(null);
                return Task.CompletedTask;
            }

            var culture = valueResult.Culture ?? CultureInfo.CurrentCulture;
            try
            {
                object? parsed = null;
                if (_targetType == typeof(decimal?))
                {
                    if (decimal.TryParse(raw, NumberStyles.Any, culture, out var v)) parsed = v;
                }
                else if (_targetType == typeof(int?))
                {
                    if (int.TryParse(raw, NumberStyles.Any, culture, out var v)) parsed = v;
                }
                else if (_targetType == typeof(long?))
                {
                    if (long.TryParse(raw, NumberStyles.Any, culture, out var v)) parsed = v;
                }
                else if (_targetType == typeof(bool?))
                {
                    if (bool.TryParse(raw, out var v)) parsed = v;
                }
                else if (_targetType == typeof(DateTime?))
                {
                    if (DateTime.TryParse(raw, culture, DateTimeStyles.AssumeLocal, out var v)) parsed = v;
                }

                if (parsed != null)
                {
                    bindingContext.Result = ModelBindingResult.Success(parsed);
                }
                else
                {
                    bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, $"值 \"{raw}\" 无法转换为 {_targetType.Name}。");
                }
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex.Message);
            }
            return Task.CompletedTask;
        }
    }

    /// <summary>
    /// Provider：为指定的可空基础类型返回 EmptyStringToNullBinder。
    /// </summary>
    public class EmptyStringToNullBinderProvider : IModelBinderProvider
    {
        public IModelBinder? GetBinder(ModelBinderProviderContext context)
        {
            var t = context.Metadata.ModelType;
            if (t == typeof(decimal?) || t == typeof(int?) || t == typeof(long?) || t == typeof(bool?) || t == typeof(DateTime?))
            {
                return new EmptyStringToNullBinder(t);
            }
            return null;
        }
    }
}
